package com.atguigu.gulimall.order.listener;

import com.atguigu.gmall.common.util.Jsons;
import com.atguigu.gulimall.order.biz.OrderBizService;
import com.atguigu.gulimall.order.to.OrderMsgTo;
import com.atguigu.gulimall.util.consts.MqConst;
import com.atguigu.gulimall.util.service.RabbitService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;

/**
 * @author nicc
 * @version 1.0
 * @className CloseOrderListener
 * @date 2022-10-25 04:11
 */

@Slf4j
@Service
public class CloseOrderListener {

    @Autowired
    private OrderBizService orderBizService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;
    /**
     * 关单监听
     * @param message
     * @param channel
     */
    @RabbitListener(queues = MqConst.ORDER_CLOSE_QUEUE)
    public void closeOrder(Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        //判断是否重复消息
//        Boolean redelivered = message.getMessageProperties().getRedelivered();
//        if(redelivered){
//
//        }
        OrderMsgTo msgTo = null;
        String json = "";
        try{
            json = new String(message.getBody());
            log.info("订单关闭消息抵达：{}",json);
            msgTo = Jsons.toObj(json, OrderMsgTo.class);
            //关闭订单
            orderBizService.closeOrder(msgTo.getOrderId(),msgTo.getUserId());
//            int i = 10/0;

            //当业务出现问题，导致消费失败，返回给MQ == 消息又抵达过来，成为一个无限死循环
            //消息重复：
            //1）、消费失败（业务失败），返回给mq服务器重新入队以后，重新派发过来
            //2）、消费成功（业务成功），没来得及回复，炸了，重新派发过来
            //现象：同一个关单消息被订单关单服务收到很多次
            //解决：
            //  1、一定保证消费消息的业务是幂等的：关单是幂等性操作；
            //  2、判断这个消息是否重复消费的。[业务、redelivered、每个消息有唯一id]
            //  3、有限次尝试。如果有消息一直失败，保存到告警库，然后人工处理

            channel.basicAck(deliveryTag,false);
            log.info("订单关闭完成：{}",msgTo);
        }catch (Exception e){
            rabbitService.retry(channel,deliveryTag,json,5);
        }
    }
}
